﻿/*
 * @author: wizardc
 */

using System;
using System.Collections.Concurrent;
using System.Threading;
using Dou.Clock;
using Dou.Utils;

namespace Dou.Sync
{
    /// <summary>
    /// 可带任意参数委托
    /// </summary>
    public delegate void PostWithParams(params object[] args);

    /// <summary>
    /// 线程同步上下文
    /// 支持当前线程向其它线程调用指定的委托方法
    /// </summary>
    public class ThreadSynchronizationContext: IClockClient
    {
        private readonly int _threadID;
        private readonly ConcurrentQueue<Action> _queue;

        /// <param name="threadID">要运行委托的线程 ID</param>
        public ThreadSynchronizationContext(int threadID)
        {
            _threadID = threadID;
            _queue = new ConcurrentQueue<Action>();
        }

        public void Post(Action action)
        {
            if (Thread.CurrentThread.ManagedThreadId == _threadID)
            {
                try
                {
                    action();
                }
                catch (Exception e)
                {
                    Log.Error(e.ToString());
                }
                return;
            }
            _queue.Enqueue(action);
        }

        public void Post(PostWithParams func, params object[] args)
        {
            Post(() => { func(args); });
        }

        /// <summary>
        /// 注意该方法必须由运行委托的线程驱动
        /// </summary>
        public void Update(float passedTime)
        {
            Action action;
            while (true)
            {
                if (!_queue.TryDequeue(out action))
                {
                    return;
                }
                try
                {
                    action();
                }
                catch (Exception e)
                {
                    Log.Error(e.ToString());
                }
            }
        }
    }
}
